#ifndef __ALTAIR_SYSTEM_MODULES_H__
#define __ALTAIR_SYSTEM_MODULES_H__

#include <stdio/fopen.h>
#include <stdio/fread.h>
#include <stdio/fclose.h>
#include <stdlib/malloc.h>
#include <altair/system/hook.h>
#include <process/seg_st.h> /* exec_set_segment_status() */

#define SEG_INT_PTR ((char)(*(unsigned int far *)((*(unsigned int far *)((long)((long)seg << 16) + 6)) + (long)((long)seg << 16))))
#define SEG_FNF_PTR (*(unsigned int far *)((long)((long)seg << 16) + 4))

/* v teto promenne jsou pointery na vsechny segmenty *:0000 */
  static unsigned int far *mod_segments[16] = {
    (unsigned int far *)0x00000000, (unsigned int far *)0x10000000,
    (unsigned int far *)0x20000000, (unsigned int far *)0x30000000,
    (unsigned int far *)0x40000000, (unsigned int far *)0x50000000,
    (unsigned int far *)0x60000000, (unsigned int far *)0x70000000,
    (unsigned int far *)0x80000000, (unsigned int far *)0x90000000,
    (unsigned int far *)0xA0000000, (unsigned int far *)0xB0000000,
    (unsigned int far *)0xC0000000, (unsigned int far *)0xD0000000,
    (unsigned int far *)0xE0000000, (unsigned int far *)0xF0000000
  };

/**
 *  near2far_memcpy()
 */
void far *near2far_memcpy(void far *dest, const void *src, unsigned int count) {
  unsigned char far *ds = (unsigned char far *)dest;
  unsigned char *ss = (unsigned char *)src;
  unsigned int i;
    for (i = 0; i < count; i++)
      ds[i] = ss[i];
    return dest;
}

/**
 *  mod_segment_stat()
 *  zjisti, jak je na tom segment <seg>, jestli je volny, nebo pouzivany
 */
unsigned char mod_segment_stat(unsigned int seg) {
  return (unsigned char)(*(mod_segments[seg >> 12]));
}

/**
 *  mod_hook()
 *  zadany soubor hookuje na dany segment
 */
char mod_hook(char *filename, unsigned int seg) {
  FILE *file;
  char *file_buff;
  unsigned int   file_size = 0;

  file = fopen(filename, "r");
  if(file == NULL)
    return 1;

  /* nacteme modul do pameti */
  file_size = fsize(file);
  file_buff = malloc(file_size+1);
  fread(file_buff, sizeof(char), file_size, file);
  fclose(file);

  /* zkopirujeme do noveho segmentu */
  near2far_memcpy((void far *)((long)((long)seg << 16)), file_buff, file_size+1);
  SetInterruptAt(
    /* 6ty bajt v aplikaci - je zde adresa na cislo interruptu, ktere
       se nahookuje */
    SEG_INT_PTR,
    /* o 4 bajty od aplikace je cislo, udavajici adresu
       funkce, ktera se bude hookovat */
    SEG_FNF_PTR,
    seg);

  /* nastavime v jadru flag, ze je segment pouzivany */
  exec_set_segment_status(seg, true);

  return 0;
}

/**
 *  mod_unhook()
 *  zadany modul odhookuje z daneho segmentu
 */
void mod_unhook(unsigned int seg) {
  /* #> 0xCF == iret */
  *(unsigned char far *)(SEG_FNF_PTR + (long)((long)seg << 16)) = (unsigned char)0xCF;

  /* #> aby byl status segmentu "UNUSABLE - nepouzitelny */
  *(unsigned char far *)((long)((long)seg << 16)) = 0x1;

  /* nastavime v jadru flag, ze se segment jiz nepouziva */
  exec_set_segment_status(seg, false);
  return;
}



#endif
